Imports Microsoft.VisualBasic
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports Cforge.Net.Mail

Namespace gvImap
	Partial Public Class ImapClient
		Private _cancelling As Boolean ' User has cancelled the operation?

		''' <summary>
		''' Sets disconnected state.
		''' </summary>
		Private Sub SetDisconnectedState()
			' Clear folder list and message list.
			listView.Items.Clear()
			treeView.Nodes.Clear()

			' Set state to not connected.
			_state = ConnectionState.NotConnected
			' Enable and disable controls.
			EnableDialog(True)

			toolStripProgressBar.Visible = False
			toolStripProgressCancelButton.Visible = False
			toolStripProgressLabel.Visible = False
			tsbLogin.Visible = True
			tsbLogout.Visible = False
			tsbRefresh.Enabled = False
			refreshToolStripMenuItem.Enabled = False
			loginToolStripMenuItem.Text = "&Login..."

			treeViewContextMenuStrip.Enabled = False
			listViewContextMenuStrip.Enabled = False

			newMailboxToolStripMenuItem.Enabled = False
			renameMailboxToolStripMenuItem.Enabled = False
			deleteMaillboxToolStripMenuItem.Enabled = False

			_currentFolder = String.Empty

			' Make sure all toolbar buttons' states are updated. 
			listView_SelectedIndexChanged(Nothing, Nothing)

			SetStatusText("Ready")
		End Sub

		Private Sub Reconnect(ByVal exc As Exception)
			If exc IsNot Nothing Then
				Util.ShowError(exc)
			End If

			treeView.Nodes.Clear()
			listView.Items.Clear()
			' Disconnect and login again.
			client.Disconnect()
			Login()
		End Sub

		''' <summary>
		''' Refreshes the folder tree view.
		''' </summary>
		Private Sub RefreshFolderList()
			RefreshFolderList(_currentFolder)
		End Sub

		''' <summary>
		''' Refreshes the folder tree view.
		''' </summary>
		''' <param name="folder">The folder name.</param>
		Private Sub RefreshFolderList(ByVal folder As String)
			' Disable controls.
			EnableDialog(False)

			If folder.Length = 0 Then
				SetStatusText("Retrieving root folder list...")
			Else
				SetStatusText("Retrieving folder list under {0}...", folder)
			End If

			Try
				' Asynchronously get folder list.
                client.BeginGetFolderList(folder, ImapFolderListOption.All, False)
			Catch exc As Exception
				Util.ShowError(exc)
				Disconnect()
			End Try
		End Sub

		''' <summary>
		''' Selects a folder.
		''' </summary>
		''' <param name="folder">The folder name. It can be 'folder1/folder11/folder111'</param>
		Private Sub SelectFolder(ByVal folder As String)
			' Split the provided folder path by '/' character.
			Dim arr() As String = folder.Split("/"c)
			Dim i As Integer = 0
			Dim nodes As TreeNodeCollection = treeView.Nodes(0).Nodes

			For Each shortname As String In arr
				For Each node As TreeNode In nodes
					If shortname = node.Text Then
						i += 1
						If i = arr.Length Then
							_noFireBeforeSelectEvent = True
							treeView.SelectedNode = node
							_noFireBeforeSelectEvent = False

							client.SelectFolder(folder)
						ElseIf (Not node.Checked) Then ' Folder list is not parsed.
							' Then retrieve a list of child folder for this node.
							Dim col As ImapFolderCollection = client.GetFolderList(CStr(node.Tag))
							For Each item As ImapFolder In col
								' Add selectable folder only.
                                If item.Selectable Then
                                    Dim n As TreeNode = node.Nodes.Add(item.ShortName)
                                    n.ImageIndex = 1
                                    n.SelectedImageIndex = 1
                                    n.Tag = item.Name
                                End If
                            Next item
                            node.Expand()
                            node.Checked = True
                            nodes = node.Nodes
                        End If
                    End If
                Next node
            Next shortname
        End Sub

        ''' <summary>
        ''' Refreshes the message list.
        ''' </summary>
        Private Sub RefreshMessageList()
            Try
                SetStatusText("Retrieving message list...")
                ' Wake up GUI.
                Application.DoEvents()
                ' Enable progress bar control.
                EnableProgress(True, client.GetFolderInfo(_currentFolder).TotalMessages)
                ' Asynchronously get message list.
                client.BeginGetMessageList(ImapMessageListOption.UniqueId)
            Catch exc As Exception
                Util.ShowError(exc)
                EnableProgress(False, 0)
            End Try
        End Sub

#Region "Event handlers"

        Private Sub client_ListProcessing(ByVal sender As Object, ByVal e As ImapListProcessingEventArgs) Handles client.ListProcessing
            If (Not IsDisposed) Then
                Invoke(New ImapListProcessingEventHandler(AddressOf ListProcessing), sender, e)
            End If
        End Sub

        ''' <summary>
        ''' Handles the client's ListProcessing event.
        ''' </summary>
        ''' <param name="sender">The client object.</param>
        ''' <param name="e"></param>
        Private Sub ListProcessing(ByVal sender As Object, ByVal e As ImapListProcessingEventArgs)
            ' If the message list is being processed and the number of processed lines is valid.
            If e.ListType = ImapListProcessingType.MessageList AndAlso toolStripProgressBar.Maximum > e.ProcessedLines AndAlso e.ProcessedLines > 0 Then
                ' Update the progress bar and progress status.
                toolStripProgressBar.Value = e.ProcessedLines
                toolStripProgressLabel.Text = String.Format("{0}/{1} message(s) processed", e.ProcessedLines, toolStripProgressBar.Maximum)
            End If
        End Sub

        ''' <summary>
        ''' Handles the client's DisconnectCompleted event.
        ''' </summary>
        ''' <param name="sender">The client object.</param>
        ''' <param name="e">The event arguments.</param>
        Private Sub client_DisconnectCompleted(ByVal sender As Object, ByVal e As ImapAsyncMethodCompletedEventArgs) Handles client.DisconnectCompleted
            Try
                ' End the async call.
                client.EndDisconnect(e.AsyncResult)
            Catch exc As Exception
                Util.ShowError(exc)
            End Try

            ' Set disconnected state.
            SetDisconnectedState()
        End Sub

        ''' <summary>
        ''' Handles the client's GetFolderListCompleted event.
        ''' </summary>
        ''' <param name="sender">The client object.</param>
        ''' <param name="e">The event arguments.</param>
        Private Sub client_GetFolderListCompleted(ByVal sender As Object, ByVal e As ImapAsyncMethodCompletedEventArgs) Handles client.GetFolderListCompleted
            Try
                ' End the async call and retrieve the folder list.
                Dim col As ImapFolderCollection = client.EndGetFolderList(e.AsyncResult)

                Dim node As TreeNode
                Dim selectNode As Boolean = False
                ' Select the right node.
                If _currentFolder.Length = 0 Then
                    node = treeView.Nodes(0)
                Else
                    node = treeView.SelectedNode

                    If node Is Nothing Then
                        node = treeView.Nodes(0)
                        selectNode = True
                    End If
                End If

                ' Clear child nodes.
                node.Nodes.Clear()

                ' Loop through the retrieved list.
                For Each i As ImapFolder In col
                    ' Add selectable node only.
                    If i.Selectable Then
                        Dim n As TreeNode = node.Nodes.Add(i.ShortName)
                        n.ImageIndex = 1
                        n.SelectedImageIndex = 1
                        n.Tag = i.Name
                    End If
                Next i
                ' Make it expanded.
                node.Expand()

                If selectNode Then
                    ' Select the current folder.
                    SelectFolder(_currentFolder)
                End If

                If _currentFolder.Length > 0 Then
                    ' Refresh the message list accordingly.
                    RefreshMessageList()
                End If
            Catch exc As Exception
                Util.ShowError(exc)
            Finally
                EnableDialog(True)
            End Try
        End Sub

        ''' <summary>
        ''' Handles the client's LoginCompleted event.
        ''' </summary>
        ''' <param name="sender">The client object.</param>
        ''' <param name="e">The event arguments.</param>
        Private Sub client_LoginCompleted(ByVal sender As Object, ByVal e As ImapAsyncMethodCompletedEventArgs) Handles client.LoginCompleted
            Try
                ' End the async call.
                client.EndLogin(e.AsyncResult)
            Catch exc As Exception
                Util.ShowError(exc)
                ' Close the connection if an error occurred.
                Disconnect()
                Return
            Finally
                EnableDialog(True)
            End Try

            ' If disconnecting
            If _state = ConnectionState.Disconnecting Then
                Disconnect()
                Return
            End If

            ' Add the user name as the root node.
            Dim node As TreeNode = treeView.Nodes.Add(_settings.UserName)
            ' Set root node image.
            node.ImageIndex = 0
            ' Selected image as well.
            node.SelectedImageIndex = 0
            ' Use Checked property as the node is Loaded state.
            node.Checked = True
            loginToolStripMenuItem.Text = "&Logout"

            ' Select the default folder.
            client.SelectFolder("INBOX")

            ' Refresh the folder list.
            RefreshFolderList(String.Empty)

            ' Set Ready state.
            SetStatusText("Ready")
            _state = ConnectionState.Ready
            ' Hide progress bar.
            toolStripProgressBar.Visible = False
            toolStripProgressCancelButton.Visible = False
            toolStripProgressLabel.Visible = False
            tsbLogin.Visible = False
            tsbLogout.Visible = True
            tsbRefresh.Enabled = True
            refreshToolStripMenuItem.Enabled = True

            treeViewContextMenuStrip.Enabled = True
            listViewContextMenuStrip.Enabled = True

            ' Focus to the tree view.
            treeView.Focus()

            ' Update states of the toolbar buttons.
            listView_SelectedIndexChanged(Nothing, Nothing)

            ' Start the session timeout timer.
            sessionTimeoutTimer.Enabled = True
            sessionTimeoutTimer.Interval = 1000
        End Sub

        ''' <summary>
        ''' Handles the client's ConnectCompleted event.
        ''' </summary>
        ''' <param name="sender">The </param>
        ''' <param name="e"></param>
        Private Sub client_ConnectCompleted(ByVal sender As Object, ByVal e As ImapAsyncMethodCompletedEventArgs) Handles client.ConnectCompleted
            Try
                ' End the async call.
                client.EndConnect(e.AsyncResult)
            Catch exc As Exception
                Util.ShowError(exc)
                Disconnect()
                Return
            End Try

            If _state = ConnectionState.Disconnecting Then
                Disconnect()
                Return
            End If
            SetStatusText("Logging in as {0}...", _settings.UserName)

            Try
                ' Asynchronously login to the IMAP server.
                client.BeginLogin(_settings.UserName, _settings.Password, _settings.Method)
            Catch exc As Exception
                Util.ShowError(exc)
                Disconnect()
            End Try
        End Sub

        Private Sub client_Progress(ByVal sender As Object, ByVal e As ImapProgressEventArgs) Handles client.Progress
            If (Not IsDisposed) Then
                Invoke(New ImapProgressEventHandler(AddressOf Progress), sender, e)
            End If
        End Sub

        ''' <summary>
        ''' Handles the client's Progress event.
        ''' </summary>
        ''' <param name="sender">The IMAP client object.</param>
        ''' <param name="e">The event arguments.</param>
        Private Sub Progress(ByVal sender As Object, ByVal e As ImapProgressEventArgs)
            If e.BytesTotal > 0 Then
                ' Update the status text.
                If e.State = ImapTransferState.Downloading Then
                    toolStripProgressLabel.Text = String.Format("{0}/{1} downloaded", Util.FormatSize(e.BytesTransferred), Util.FormatSize(e.BytesTotal))
                Else
                    toolStripProgressLabel.Text = String.Format("{0}/{1} uploaded", Util.FormatSize(e.BytesTransferred), Util.FormatSize(e.BytesTotal))
                End If

                Dim value As Integer = CInt(Fix(e.BytesTransferred * 100 / e.BytesTotal))
                If value > 100 Then
                    value = 100
                End If
                toolStripProgressBar.Value = value
                ' Wake up GUI.
                Application.DoEvents()
            End If
        End Sub

        ''' <summary>
        ''' Handles the client's GetMessageListCompleted event.
        ''' </summary>
        ''' <param name="sender">The client object.</param>
        ''' <param name="e">The event arguments.</param>
        Private Sub client_GetMessageListCompleted(ByVal sender As Object, ByVal e As ImapAsyncMethodCompletedEventArgs) Handles client.GetMessageListCompleted
            Try
                ' End the async call.
                Dim col As ImapMessageCollection = client.EndGetMessageList(e.AsyncResult)

                ' Clear the message list.
                listView.Items.Clear()

                ' Update the progress bar control.
                toolStripProgressBar.Maximum = col.Count
                toolStripProgressBar.Value = 0
                Dim value As Integer = 0

                For Each m As ImapMessage In col
                    ' User has cancelled the operation?
                    If _cancelling Then
                        Exit For
                    End If

                    Dim msg As ImapMessage = Nothing
                    Try
                        ' Retrieve message information.
                        msg = client.GetMessageInfo(m.UniqueId, ImapMessageListOption.Envelope)
                    Catch
                    End Try

                    If msg IsNot Nothing Then
                        value += 1

                        ' If From property is empty then use the Sender property.
                        Dim From As String = msg.From.ToString()
                        If From.Length = 0 AndAlso msg.Sender IsNot Nothing Then
                            From = msg.Sender.ToString()
                        End If
                        Dim arr() As String
                        If msg.Date IsNot Nothing Then
                            If (msg.Flags And ImapMessageFlags.Deleted) <> 0 Then
                                arr = New String() {From, msg.Subject, msg.Date.ToString(), "Delete", Util.FormatSize(msg.Length)}
                            Else
                                arr = New String() {From, msg.Subject, msg.Date.ToString(), String.Empty, Util.FormatSize(msg.Length)}
                            End If
                        Else
                            If (msg.Flags And ImapMessageFlags.Deleted) <> 0 Then
                                arr = New String() {From, msg.Subject, "1/1/1900", "Delete", Util.FormatSize(msg.Length)}
                            Else
                                arr = New String() {From, msg.Subject, "1/1/1900", String.Empty, Util.FormatSize(msg.Length)}
                            End If
                        End If
                        Dim item As New ListViewItem(arr)
                        If (msg.Flags And ImapMessageFlags.Seen) = 0 Then
                            ' New message.
                            item.Font = New Font(item.Font, item.Font.Style Or FontStyle.Bold)
                            item.ImageIndex = 2
                        Else
                            ' Seen message.
                            item.ImageIndex = 3
                        End If
                        item.Tag = New ListItemTagInfo(msg.SequenceNumber, msg.UniqueId, msg.Date, msg.Length)

                        ' Add to the list.
                        listView.Items.Add(item)
                        ' Update the status text.
                        toolStripProgressLabel.Text = String.Format("{0}/{1} message(s) retrieved", value, col.Count)
                    Else
                        toolStripProgressBar.Maximum -= 1
                    End If
                    If value < toolStripProgressBar.Maximum Then
                        toolStripProgressBar.Value = value
                    End If

                    ' Wake up GUI.
                    Application.DoEvents()
                Next m
            Catch exc As Exception
                Dim ie As ImapException = TryCast(exc, ImapException)
                If ie Is Nothing OrElse ie.Status <> ImapExceptionStatus.OperationAborted Then
                    Util.ShowError(exc)
                    Return
                End If
            Finally
                EnableProgress(False, 0)
            End Try

            If _state = ConnectionState.Disconnecting Then
                Disconnect()
                Return
            End If

            ' Update the state.
            listView_SelectedIndexChanged(Nothing, Nothing)
        End Sub

#End Region

		#Region "Folder"

		''' <summary>
		''' Deletes the selected folder.
		''' </summary>
		Private Sub DeleteFolder()
			Dim folder As String = _currentFolder

			EnableDialog(False)

			Try
				SetStatusText("Deleting folder {0}...", folder)
				Application.DoEvents()
				client.DeleteFolder(folder)

				'//if (folder == _currentFolder)
				'//{
				'    _currentFolder = (string)treeView.SelectedNode.Parent.Tag;
				'    if (_currentFolder == null)
				'        _currentFolder = string.Empty;
				'//}

				treeView.SelectedNode.Parent.Checked = False ' Reset folder list downloaded state.
				treeView.SelectedNode = treeView.SelectedNode.Parent

				'RefreshFolderList();
			Catch exc As Exception
				Util.ShowError(exc)
			Finally
				EnableDialog(True)
			End Try
		End Sub

		''' <summary>
		''' Creates a new folder.
		''' </summary>
		Private Sub NewFolder()
			Try
				' Create a new TreeNode.
				Dim node As New TreeNode()
				' Get the parent node.
				Dim parent As TreeNode = treeView.SelectedNode
				parent.Nodes.Add(node)
				node.ImageIndex = 1
				node.SelectedImageIndex = 1
				' Expand the parent node.
				parent.Expand()
				' Begin edit folder name.
				node.BeginEdit()
			Catch exc As Exception
				Util.ShowError(exc)
			End Try
		End Sub

		''' <summary>
		''' Purges all messages that are marked as delete.
		''' </summary>
		Private Sub PurgeMessages()
			Try
				' Purge messages.
				client.Purge()
				' Refresh the message list.
				RefreshMessageList()
			Catch exc As Exception
				Util.ShowError(exc)
			End Try
		End Sub

		#End Region

		#Region "Message"

		''' <summary>
		''' Uploads message from local file.
		''' </summary>
		Private Sub UploadMessage()
			Dim dlg As New OpenFileDialog()
			dlg.Filter = "Email files (*.eml)|*.eml|All files (*.*)|*.*"
			dlg.FilterIndex = 1
			' Show open file dialog to select file to upload.
			If dlg.ShowDialog() = DialogResult.OK Then
				Try
					EnableProgress(True, 100)
					Application.DoEvents()

					' Upload the selected message file.
					client.UploadMessage(_currentFolder, dlg.FileName)
					RefreshMessageList()
				Catch exc As Exception
					Reconnect(exc)
				Finally
					EnableProgress(False, 0)
				End Try
			End If
		End Sub

		''' <summary>
		''' Deletes selected messages.
		''' </summary>
		Private Sub DeleteMessages()
			' Show a confirmation message box.
			If MessageBox.Show(String.Format("Are you sure you want to delete {0} message(s)?", listView.SelectedItems.Count), "Imap Client Demo", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.No Then
				Return
			End If

			' Enable progress bar, and disable other controls.
			EnableProgress(True, listView.SelectedItems.Count)
			Try
				Dim value As Integer = 0
				For Each item As ListViewItem In listView.SelectedItems
					' User has cancelled the operation?
					If _cancelling Then
						Exit For
					End If
					Application.DoEvents()
					' Delete a message.
                    client.DeleteMessage((CType(item.Tag, ListItemTagInfo)).SequenceNumber)
                    _messagesDelete = True
					item.SubItems(3).Text = "Delete"
					item.Font = New Font(item.Font, item.Font.Style Or FontStyle.Strikeout)
					value += 1
					toolStripProgressBar.Value = value
					toolStripProgressLabel.Text = String.Format("{0}/{1} message(s) deleted", value, listView.SelectedItems.Count)
				Next item
			Catch exc As Exception
				Reconnect(exc)
			Finally
				EnableProgress(False, 0)
			End Try
		End Sub

		''' <summary>
		''' Undeletes messages.
		''' </summary>
		Private Sub UndeleteMessages()
			' Enable progress bar and disable other controls.
			EnableProgress(True, listView.SelectedItems.Count)
			Try
				Dim value As Integer = 0
				For Each item As ListViewItem In listView.SelectedItems
					' User has cancelled the operation.
					If _cancelling Then
						Exit For
					End If
					' Wake up GUI.
					Application.DoEvents()
					' Undelete the selected messages.
					client.UndeleteMessage((CType(item.Tag, ListItemTagInfo)).SequenceNumber)
					item.SubItems(3).Text = String.Empty
					item.Font = New Font(item.Font, (item.Font.Style Or FontStyle.Strikeout) Xor FontStyle.Strikeout)
					' Update the progress bar and progress status.
					value += 1
					toolStripProgressBar.Value = value
					toolStripProgressLabel.Text = String.Format("{0}/{1} message(s) undeleted", value, listView.SelectedItems.Count)
				Next item
			Catch exc As Exception
				Util.ShowError(exc)
			Finally
				EnableProgress(False, 0)
			End Try
		End Sub

		Private _copyFolder As String
		Private _copyInfo As ImapMessageSet
		''' <summary>
		''' Copies messages
		''' </summary>
		Private Sub CopyMessage()
			' Create a new ImapMessageSet that contains information about the messages being copied.
			_copyInfo = New ImapMessageSet()
			' Add selected messages to the message set;
			For Each item As ListViewItem In listView.SelectedItems
				_copyInfo.Add((CType(item.Tag, ListItemTagInfo)).UniqueId)
			Next item
			' Save the selected folder.
			_copyFolder = _currentFolder
		End Sub

		''' <summary>
		''' Pastes the copied messages to the specified destination folder.
		''' </summary>
		''' <param name="destFolder">The destination folder that stores the copied messages.</param>
		Public Sub PasteMessage(ByVal destFolder As String)
			' Select the previously selected folder.
			client.SelectFolder(_copyFolder)
			' Copy messages.
			client.CopyMessage(_copyInfo, destFolder)
			' Select the current working folder.
			client.SelectFolder(_currentFolder)

			' Refresh the message list.
			RefreshMessageList()
		End Sub

		#End Region
	End Class
End Namespace
